/*  This file is part of the OpenLB library
 *
 *  Copyright (C) 2009 Mathias J. Krause
 *  E-mail contact: info@openlb.net
 *  The most recent release of OpenLB can be downloaded at
 *  <http://www.openlb.net/>
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public
 *  License along with this program; if not, write to the Free
 *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA  02110-1301, USA.
 */

/** \file
 * Reader for Nastran 3D voxel mesh files
 * generated by HyperMesh -- header file.
 */

#ifndef Nastran_Voxel_Mesh_Reader_3D_H
#define Nastran_Voxel_Mesh_Reader_3D_H

#include <vector>
#include <map>
#include <string>

//#include "olb3D.h"
//#include "olb3D.hh"

#include "../core/blockGeometry3D.h"
#include "io/ostreamManager.h"

/// All OpenLB code is contained in this namespace.
namespace olb {

/// Reader for Nastran 3D voxel mesh files generated by HyperMesh
/** The NastranVoxelMeshReader3D reads designated NASTRAN files.
 *
 * There are three precondition for the Nastran files:<br>
 * 1. The grid points are given in long format which is indicated
 *    by the keyword GRID*<br>
 * 2. The underlying mesh consists of regular hexahedrons (CHEXA).<br>
 * 3. With the help of the keyword HMMOVE a number can be assigned
 *    to each of the CHEXA. Later, this number represents the type
 *    of a CHEXA, e.g. 0      -> No Fluid Voxel,
 *                     1      -> Fluid Voxel,
 *                     2,3,.. -> Bounder Voxel Type 1,2,..
 *    (In the software package HyperMesh the particular number
 *    is represented by the ID of a COMPONENT to which the
 *    hexahedrons can be assigned to.)
 *
 * Two important function are provided by this class:
 *  1. void writeVtiFile()
 *  2. olb::ScalarField3D<int>* getGeometryData()
 *
 * This class is not intended to be derived from.
 */

class NastranVoxelMeshReader3D {

private:
  /// class specific ostream
  mutable OstreamManager clout;
  /// Input file name
  std::string _fileName;
  /// Position of voxel (0/0/0)
  double _x0, _y0, _z0;
  /// Spacing
  double _h;
  /// Number of voxel in each direction
  int _nx, _ny, _nz;
  /// Size of ghost voxel layer
  int _offset;

  /// A voxel coordinate is mapped to its colour
  std::map<std::vector<unsigned short>, unsigned short> _voxel2colour;

  /// Helper function: Converts a substring to a value of type T
  ///and returns it
  template<typename T>
  T extractValue(std::string str, int begin, int length);
  /// Helper function: Writes all lines in a file to a vector and
  ///returns it
  std::vector<std::string> linesOfFile2Vector(std::string fileName);

  /// Nastran helper functions: Writes the data of a line beginning
  /// with "GRID*" to the map (PointID->(x/y/z) )
  void
  writeGridPoint(std::vector<std::string>::iterator &lineIter,
                 std::map<int, std::vector<double> > &pointID2data);
  /// Nastran helper functions: Writes the data of a line beginning
  /// with "CQUAD4" to the map (QuadID->(PointID1/PointID2/PointID3
  /// /PointID4) )
  void writeQuad(std::vector<std::string>::iterator &lineIter, std::map<int, std::vector<int> > &quadID2data);
  /// Nastran helper functions: Writes the data of a line beginning
  /// with "CHEXA" to the map (HexaID->(PointID1/.../PointID8/
  /// Colour) ), where Colour is set to zero
  void writeHexa(std::vector<std::string>::iterator &lineIter, std::map<int, std::vector<int> > &hexaID2data);
  /// Nastran helper functions: Writes the data of a line beginning
  /// with "$HMMOVE" to the map (HexaID->(PointID1/.../PointID8
  /// /Colour) ),
  /// where only Colour is change to the here specified value
  void writeHexaColor(std::vector<std::string>::iterator &lineIter, std::map<int, std::vector<int> > &hexaID2data);
  /// Nastran helper functions: Initialises x0, y0, z0, h , nx, ny
  /// and nz
  void computeMotherCuboid(std::map<int, std::vector<double> > &pointID2data,
                           std::map<int, std::vector<int> > &hexaID2data);
  /// Nastran helper functions: Fills the map _voxel2colour
  void computeVoxelColour(std::map<int, std::vector<double> > &pointID2data,
                          std::map<int, std::vector<int> > &hexaID2data);

public:
  /// Constructor
  NastranVoxelMeshReader3D(std::string& fileName, int offset = 0);
  /// Destructor
  ~NastranVoxelMeshReader3D();

  ///
  void setColour(unsigned short iX, unsigned short iY, unsigned short iZ, unsigned short colour);

  ///
  unsigned short getColour(unsigned short iX, unsigned short iY, unsigned short iZ);

  /// Adds a boundary layer
  void addBoundaryLayer(unsigned short from, unsigned short to, unsigned short closeTo);

  // Reads Nastran file
  //template <typename T>
  //void readNastranFile(/*CuboidGeometry3D<T>* _cuboidGeometry*/);
  /// Reads Nastran file
  void readNastranFile(BlockGeometry3D* blockGeometry);
  /// Writes a VTI file with name _fileNam+"vti"
  void writeVtiFile();
};

} // namespace olb

#endif
